package gui;

import generator.CubeBuilder;
import io.CubeRW;
import model.*;

import java.awt.Color;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;

import javax.swing.BorderFactory;
import javax.swing.ButtonGroup;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.WindowConstants;

/**
 * Osztály, amely grafikus felületet tartalmaz.
 *  Segítségével adott méretű soma kocka kirakósokat lehet generálni és elmenteni azokat fájlokba, 
 *  hogy majd onnan olvassuk ki őket a játszáshoz (megjelenítéshez).
 */
public class GUI {
	/**A fő keret, mely tartalmazza a grafikus komponenseket.*/
	private JFrame frame;
	/**Gombok:
	 * 		general - kocka kirakós generálására,
	 * 		kilep - a játékból való kilépéshez,
	 * 		jatek - a játék (megjelenítés) elindításához.
	 * */
	private JButton general, kilep, jatek;
	/**Panelek:
	 * 		content - a fő keret konténere,
	 * 		radioPanel - a radiógombok tárolására, melyek a méret kiválasztásához szükségesek,
	 * 		p - a képet tartalmazza.
	 * */
	private JPanel content, radioPanel, p;
	/**Címke, mely a háttérképet tartalmazza.*/
	private JLabel image;
	/**Rádiógombok, melyek a kocka méretének kiválasztásához szükségesek.*/
	private JRadioButton rb3, rb4, rb5, rb6;
	/**A rádiógombok csoportos, egységes kezelése.*/
	private ButtonGroup bgroup;

	/**A kocka kirakós megoldásának előállításához szükséges osztály.*/
	private SolveCube solve;
	/**A kocka kirakós generálásához szükséges osztály.*/
	private CubeBuilder build;
	/**A kocka kirakór fájlokba való kiiratásához szükséges osztály.*/
	private CubeRW rw;
	/**A generált és a megoldott puzzle-darabok tárolására alkalmas tömbök.*/
	private Matrix3D [] cubes, solution;

	/**
	 * Az osztály konstruktora. Létrehozza a grafikus komponenseket, megjeleníti őket a fő kereten
	 * és figyeli a gombok működését.
	 * */
	public GUI() {
		createComponents();
		addComponents();
		setProperties();
		gombFigyelok();
	}
	
	/**
	 * A grafikus komponensek létrehozásáért felelős metódus. Példányosítja a fő keretet, a gombokat, 
	 * a rádiógombokat és az azokhoz szükséges panelt, lekéri a háttérképet.
	 * */
	private void createComponents() {
		frame = new JFrame("Soma kockák generálása");
		general = new JButton("Generál");
		kilep = new JButton("Kilépés");
		jatek = new JButton("Játék");
		content = new JPanel();
		content.setLayout(null);
		frame.setContentPane(content);
		radioPanel = new JPanel();
		radioPanel.setLayout(new GridLayout(4, 1, 20, 3));
		rb3 = new JRadioButton("3", true);
		rb4 = new JRadioButton("4", false);
		rb5 = new JRadioButton("5", false);
		rb6 = new JRadioButton("6", false);
		bgroup = new ButtonGroup();	
		p = new JPanel();
		p.setLayout(null);
		image = new JLabel(new ImageIcon("soma7.jpg"));
	}
	
	/**
	 * A grafikus komponensek fő kerethez való hozzáadásáért felelős metódus.
	 */
	private void addComponents() {
		// a rádiógombok háttérszínének beállítása
		rb3.setBackground(new Color(180,230,200));
		rb4.setBackground(new Color(180,230,200));
		rb5.setBackground(new Color(180,230,200));
		rb6.setBackground(new Color(180,230,200));
		// A 4 rádiógomb hozzáadása a gomb-csoporthoz, hogy egységesen kezeljük őket. 
		//	Vagyis egyszerre csak egy gomgot lehessen kijelölni.
		bgroup.add(rb3);
		bgroup.add(rb4);
		bgroup.add(rb5);
		bgroup.add(rb6);
		// a rádiógombok hozzáadása a panelhez.
		radioPanel.add(rb3);
		radioPanel.add(rb4);
		radioPanel.add(rb5);
		radioPanel.add(rb6);
		
		// a rádiógombokat tartalmazó panel méretének, helyének és hátterének beállítása.
		radioPanel.setBounds(35, 30, 110, 150);
		radioPanel.setBackground(new Color(180,230,200));
		p.add(radioPanel);
		// a Generálás gomb méretének beállítása
		general.setBounds(35, 200, 100, 35);
		// a Generálás gomb hozzáadása a p panelhez
		p.add(general);
		// a Kilépés gomb méretének beállítása
		kilep.setBounds(35, 310, 100, 35);
		// a Kilépés gomb hozzáadása a p panelhez
		p.add(kilep);
		// a Játék gomb méretének beállítása
		jatek.setBounds(35, 240, 100, 35);
		// a JATEK GOMB HOZZAADASA a p panelhez
		//p.add(jatek);
		// a p panel méretének beállítása
		p.setBounds(0, 0, 180, 400);
		// a p panel hátterének beállítása
		p.setBackground(new Color(180, 230, 255));
		// a p panel hozzáadása a fő keret konténeréhez
		content.add(p);
		// a képet tartalmazó címke méretének beállítása
		image.setBounds(180,0,400,370);
		// a képet tartalmazó címke hozzáadása a konténerhez
		content.add(image);
	}
	
	/**
	 * A fő keret jellemzőinek beállításáért felelős metódus.
	 */
	private void setProperties() {
		// beállítjuk a rádiógombokat tartalmazó panel szélét
		radioPanel.setBorder(BorderFactory.createTitledBorder(
		           BorderFactory.createEtchedBorder(), "Válassz méretet"));
		frame.pack();
		frame.setBounds(10, 10, 600, 400);
		frame.setVisible(true);
		frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
	}
	
	/**
	 * A gombok működésének figyeléséért felelős metódus.
	 * A Generálás gomb a legfontosabb: a rádiógombok segítségével megadott méretű 
	 * kockakirakóst generálunk, előállítjuk ennek megoldását és kiírjuk ezeket fájlba.
	 */
	private void gombFigyelok() {
		// a Kilépés gomb figyelőjének definiálása - kilépünk a programból
		kilep.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				System.exit(0);
			}
		});
		
		// a Generálás gomb figyelőjének definiálása
		general.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				// lekérjük a kiválasztott méretet a rádiógomboktól egy metódus segítségével.
				int number = meret();
				// lekérjük a rendszeridőt, hogy tudjuk majd kiszámolni a generáláshoz és a
				//	  megoldás előállításához szükséges időmennyiséget
				long stime=System.currentTimeMillis();
				// kocka kirakós generálásáért felelős osztály példányosítása a megfelelő mérettel
				//	  (a méretet a rádiógomboktól kértük le)
				build = new CubeBuilder(number);
				// kocka kirakóst generálunk
				build.build();
				build.separate();
				
				// lekérjuk a generált puzzle darabjainak számát
				int n = build.getPieceNum();
				// létrehozunk egy tömböt a darabok tárolására
				cubes = new Matrix3D[n];
				// egyenként lekérjük az összes darabot
				for (int i=0; i < n; ++i) {
					cubes[i] = new Matrix3D(number);
					cubes[i] = build.getFinalPieces()[i].getCube();
				}
				// kocka kirakós megoldásáért felelős osztály példányosítása. 
				//    A paraméterek az előbb generált darabokra és ezek számára.
				if (number!=6) { // csak akkor ha n nem 6, kulonben lefagy (Out of memory)
					solve = new SolveCube(cubes, n);
					// lekérjük a megoldást
					solution = solve.getSolutions3D();
				}
				// létrehozzuk a fájlokba való kiiratásért felelős osztály egy példányát.
				rw = new CubeRW();
				// kiírjuk fájlokba a generált darabokat és a megoldást
				rw.writePuzzle(cubes, solution);
				// lekérjük ismét a rendszeridőt
				long time=System.currentTimeMillis()-stime;
				// kiírunk egy üzenetet, hogy a gép munkája véget ért és kiírjuk az eltelt időt is.
				JOptionPane.showMessageDialog(frame, "A(z) " + number + "x" + number + "x" + number + "-s méretű kocka kirakós generálása és a megoldás megtalálása befejeződött "+(time/1000F)+" másodperc alatt!","Üzenet", 1);	
			}
		});
		
		// a Játék gomb figyelőjének definiálása.
		jatek.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				// A Játék gomb figyelőjének megadása: 
				//	  indítjuk a megjelenítést, hogy játszhassunk.
				try {
					Runtime.getRuntime().exec( "../../../../../PFFF/PFFF/bin/x86/Debug/PFFF.exe" );
				} catch (IOException e1) {
					e1.printStackTrace();
				}
			}
		});
	}
	
	/**
	 * A kiválasztott rádiógombhoz tartozó méretet téríti vissza.
	 * @return
	 */
	public int meret() {
		// feltételezzük, hogy a 3-as van kijelölve és megnézzük, hogy a 4, 5, 6 közül nincse valamelyik kijelölve
		//	  és megfelelően állítjuk a n-t
		int n = 3;
		if (rb4.isSelected()) n = 4;
		if (rb5.isSelected()) n = 5;
		if (rb6.isSelected()) n = 6;	
		return n;
	}
	
	/**
	 * A fő metódus: egy új példány hozunk létre az osztályból.
	 * Lehetőség van egy megadott útvonal alapján puzzle beolvasására fájlokból, 
	 * a megoldásának előállítására és a fájlrendszerbe való beírására is.
	 * @param args - a parancssor argumentumai
	 */
	public static void main(String [] args) {
		new GUI();		
		/*
		SolveCube solve;
		CubeRW rw;
		Matrix3D [] cubes, solution;
		rw = new CubeRW();
		cubes = rw.readPuzzleFromFile("file/1", 6, 3);
		solve = new SolveCube(cubes, 6);
		solution = solve.getSolutions3D();
		//create writer
		rw.writePuzzle(cubes, solution);
	*/
	}
}
